/* program2 和program3 的头文件
    一共有三个文件:
    1.sharedspace.h
    2.creator.c 创建共享内存并初始化静态链表
    3.conncector.c 建立终端进行并发操作
*/

/*1.sharedspace.h
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

// the queue's max size;
#define MAXSTUDENTNUM 8
#define MAX_NAME_LENGTH 16

#define PERM S_IRUSR|S_IWUSR|IPC_CREAT

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

//学生信息结点
struct student {
	//data
	int id;
	char name[MAX_NAME_LENGTH];
	//删除标志,-1代表已经删除/元素不存在,0代表拥有元素
	int flag;
};

//静态链表结构,在其上建立一个堆结构
struct static_link_list {
	int capacity;
	//信息结构
	struct student students[MAXSTUDENTNUM + 1];
};

//共享内存空间,包括一个lock和一个共享内存区域M
struct shared_space {
	int lock;
	struct static_link_list L;
};

typedef struct student Student;
typedef struct shared_space SharedSpace;
typedef struct static_link_list StaticLinkList;

//本进程测试用,模拟共享内存
// SharedSpace* create_shared_space() {
// 	SharedSpace* s = (SharedSpace*)malloc(sizeof(SharedSpace));
// 	return s;
// }



//初始化静态链表
void initializeStaticLinkList(StaticLinkList* L) {
	L->capacity = MAXSTUDENTNUM;
	for (int i = 0; i < MAXSTUDENTNUM + 1; i++) {
		L->students[i].flag = -1;
		L->students[i].id = 0;
		strcpy(L->students[i].name, "null");
	}
	//头结点存储堆结构的长度
	L->students[0].flag = 0;
}

//初始化共享内存空间
void initializeSharedSpace(SharedSpace* s) {
	s->lock = 0;
	initializeStaticLinkList(&s->L);
}


//小顶堆push操作
int push(StaticLinkList*L,Student s) {
	if (L->capacity == L->students[0].flag) {
		printf("push()\n");
		return -1;
	}
	else {
		int key = s.id;
		int lastElementIndex = ++L->students[0].flag;
		int i = lastElementIndex;
		for (; L->students[i / 2].id > key; i /= 2) {
			L->students[i] = L->students[i / 2];
		}
		L->students[i] = s;
		return 0;
	}
}

//小顶堆pop操作
Student* pop(StaticLinkList*L) {
	if(L->students[0].flag == 0){
		printf("pop()\n");
		return &L->students[0];
	}
	
	Student* topStudent = (Student*)malloc(sizeof(Student));
	strcpy(topStudent->name,L->students[1].name);
	topStudent->id = L->students[1].id;
	topStudent->flag = L->students[1].flag;
	Student lastStudent = L->students[L->students[0].flag];
	L->students[L->students[0].flag].flag = -1;
	int lastElementIndex = L->students[0].flag -- ;
	int childIndex;
	int i = 1;
	for (; i * 2 < lastElementIndex; i = childIndex) {
		childIndex = i * 2;
		if (childIndex != lastElementIndex
			&& L->students[childIndex + 1].id < L->students[childIndex].id) {
			childIndex++;
		}
		if (lastStudent.id > L->students[childIndex].id) {
			L->students[i] = L->students[childIndex];
		}
		else {
			break;
		}
	}
	L->students[i] = lastStudent;
	return topStudent;
}

//静态链表查询操作
Student* find(StaticLinkList* L, int id) {
	for (int i = 0; i < L->capacity; i++) {
		if (L->students[i].id == id) {
			return &L->students[i];
		}
	}
	return &L->students[0];
}

//静态链表更新操作
int update(StaticLinkList*L, int id ,Student newStd) {
	Student* s_ptr = find(L, id);
	if (s_ptr->id != 0) {
		*s_ptr = newStd;
		printf("[update] 1 item.\n");
		return 0;
	}
	else {
		return -1;
	}
}

//根据用户输入查询相关信息
int findItem(SharedSpace* shared) {
	printf(">>>>>>Find[id] :");
	int id;
	scanf("%d",&id);
	Student* s_ptr = find(&shared->L, id);
	if(s_ptr->id==0){
		return -1;
	}
	printf("[Find] id=%d:\n",id);
	printf("[Result] id=%d,name=%s\n",s_ptr->id,s_ptr->name);
	return 0;
}

//根据用户输入更新相关信息
int updateItem(SharedSpace* shared){
	printf(">>>>>>Update[id name] :");
	char name_str[MAX_NAME_LENGTH];
	int sid;
	scanf("%d %s", &sid, name_str);
	Student std;
	std.id = sid;
	strcpy(std.name, name_str);
	while (shared->lock == 1)
	{
		sleep(3);
	}
	shared->lock = 1;
	if (update(&shared->L, std.id,std) != -1) {
		printf("[Update] id=%d,name=%s\n",std.id,std.name);
	}
	shared->lock = 0;
	return 0;
}

//根据用户输入插入学生信息
int insert(SharedSpace* shared) {
	printf("Insert[id name]>>>:");
	char name_str[MAX_NAME_LENGTH];
	int sid;
	scanf("%d %s", &sid, name_str);
	Student std;
	std.id = sid;
	strcpy(std.name, name_str);
	while (shared->lock == 1)
	{
		sleep(3);
	}
	shared->lock = 1;
	if (push(&shared->L, std) != -1) {
		printf("[Insert] id=%d,name=%s\n",std.id,std.name);
	}
	shared->lock = 0;
	return 0;
}

//删除堆顶结点
Student* deleteMin(SharedSpace*s) {
	s->lock = 1;
	Student* std = pop(&s->L);
	printf("[Delete] id=%d,name=%s\n", std->id, std->name);
	s->lock = 0;
	return std;
}

//展示静态链表的结构
void showTable(SharedSpace* shared) {
	StaticLinkList*L = &shared->L;
	for (int i = 1; i < L->students[0].flag+1; i++) {
		printf("[%d] id=%d;name=%s\n", i,L->students[i].id, L->students[i].name);
	}
}

//展示选项
void showOperation() {
	printf("------------------------------------\n");
	printf("i [ID NAME]插入.\n");
	printf("p 查看链表.\n");
	printf("u [ID NAME] 更新学号为ID的学生,修改姓名为NAME.\n");
	printf("f [ID] 查找学号为ID的学生.\n");
	printf("d 删除学号最小的学生.\n");
	printf("h 查看命令.\n");
	printf("------------------------------------\n");
}

//根据用户输入进行相关操作
void makeDecision(SharedSpace* shared,char choice) {
	if(choice=='\0'||choice=='\n'){
		return;
	}
	switch (choice)
	{
		case 'i':
			insert(shared);
			break;
		case 'd': 
			deleteMin(shared);
			break;
		case 'p': 
			showTable(shared);
			break;
		case 'f': 
			findItem(shared);
			break;
		case 'u': 
			updateItem(shared);
			break;
		case 'h':
			showOperation();
			break;
		default:
			printf("输入不合法.请重试\n");
			break;
	}
}

*/


/*
    2.creator.c 
*/

/*
    创建共享内存空间M并初始化静态链表结构L，
    并在L上建立一个二元小顶堆。
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <fcntl.h>

#include "sharedspace.h"

//测试样例 
Student testcases[12] = {
	{1,"s1"},{30,"s2"},{2,"s3"},{40,"s4"},{50,"s5"},{4,"s6"},{3,"s7"},{60,"s8"},{80,"s9"},{90,"s10"},{100,"s11"},{5,"s12"}
};

void insertTestCase(SharedSpace* shared){
    printf("[Insert] 12 test cases...\n");
    for(int i = 0;i<12;i++){
        push(&shared->L, testcases[i]);
    }
}

int main(int argc, char *argv[])
{
    struct stat fileattr;
    key_t key; /* of type int */
    int shmid; /* shared memory ID */
    void *shmptr;

    struct shared_space *shared; /* structured shm */

    pid_t childpid1, childpid2;
    char pathname[80], key_str[10], cmd_str[80];
    int shmsize, ret;

    //shmsize = TEXT_NUM*sizeof(struct shared_struct);
    shmsize = sizeof(struct shared_space);
    printf("max record number = %d, shm size = %d\n", MAXSTUDENTNUM, shmsize);

    if(argc <2) {
        printf("Usage: ./a.out pathname\n");
        return EXIT_FAILURE;
    }
    strcpy(pathname, argv[1]);

    if(stat(pathname, &fileattr) == -1) {
        //if don't insist then create a file;
        ret = creat(pathname, O_RDWR);
        if (ret == -1) {
            ERR_EXIT("creat()");
        }
        printf("shared file object created\n");
    }
 
    key = ftok(pathname, 0x27); /* 0x27 a project ID 0x0001 - 0xffff, 8 least bits used */
    if(key == -1) {
        ERR_EXIT("shmcon: ftok()");
    }
    printf("key generated: IPC key = %x\n", key); /* can set any nonzero key without ftok()*/

    shmid = shmget((key_t)key, shmsize, 0666|PERM);
    if(shmid == -1) {
        ERR_EXIT("shmcon: shmget()");
    }
    printf("shmcon: shmid = %d\n", shmid);

    shmptr = shmat(shmid, 0, 0); /* returns the virtual base address mapping to the shared memory, *shmaddr=0 decided by kernel */

    if(shmptr == (void *)-1) {
        ERR_EXIT("shmcon: shmat()");
    }
    printf("shmcon: shared Memory attached at %p\n", shmptr);
    
    //初始化共享内存空间
    shared = (struct shared_space*)shmptr;
	initializeSharedSpace(shared);
    //insert test cases;
    insertTestCase(shared);

    
    sprintf(cmd_str, "ipcs -m | grep '%d'\n", shmid); 
    printf("\n------ Shared Memory Segments ------\n");
    system(cmd_str);
	
    if(shmdt(shmptr) == -1) {
        ERR_EXIT("shmcon: shmdt()");
    }

    printf("\n------ Shared Memory Segments ------\n");
    system(cmd_str);

    sprintf(key_str, "%x", key);
    char *argv1[] = {" ", key_str, 0};

    printf("[TESTING POINT]\n");

    //经过长时间后回收共享内存
    sleep(300);
    if (shmctl(shmid, IPC_RMID, 0) == -1) {
        ERR_EXIT("shmcon: shmctl(IPC_RMID)");
    }
    else {
        printf("shmcon: shmid = %d removed \n", shmid);
        printf("\n------ Shared Memory Segments ------\n");
        system(cmd_str);
        printf("nothing found ...\n"); 
    }
    exit(EXIT_SUCCESS);
}

